home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 4
/
Amiga Tools 4.iso
/
tools
/
disk-tools
/
misc
/
scsidevs
/
scsidevs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-26
|
19KB
|
1,022 lines
#define VERSION "1.2"
/*
***** SCSIdevs
*
* Scans the SCSI bus looking for devices and reports on those found.
* If the device has a RDB, bits of it are printed out.
*
* Usage:
*
* SCSIdevs [-d<scsi-device-name>]
*
*
* options;
*
* -d<scsi_device_name> ; (default = *scsi*.device)
*
*
***** Written by Gary Duncan
*
* Bug reports etc via e-mail to gduncan@werple.net.au)
*
***** Mod record
*
* Version Date Changes
* ~~~~~~~ ~~~~ ~~~~~~~
*
* 1.0 01Nov95 Original
* 1.1 01Dec95 Better parsing for *scsi*.device
* 1.2 09Dec95 Match Open/CloseDevice calls
*
*
***** Freely distributable for non-commercial purposes
*
* Compiles under SAS/C 6.x
*
*
*
***** Function List :-
*/
/***
main ()
init ()
read_sec_scsi ()
GetDevName ()
err_str ()
sense_errs ()
check_scsi_devices ()
print_rdsk_info ()
print_Part_info ()
print_env_buf ()
b2Cstr ()
mkCstr ()
checksum ()
hexit ()
usage ()
***/
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <dos/filehandler.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <devices/trackdisk.h>
#include <libraries/dosextens.h>
#include <devices/scsidisk.h>
#include <devices/hardblocks.h>
#include <libraries/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include "typedefs.h"
#include "scsi_priv.h"
typedef struct SCSICmd SCSICMD;
typedef enum
{
GOOD, NO_DEV, NO_RDB, SCSI_ERR
}
RET_VAL;
char inq_buf[8 * MAX_DATA_LEN];
#define SEC_LEN_512 512
#include "Proto/SCSIDevs_protos.h"
static IDTOSTRING devicetype[] =
{
0x00, "Disk ",
0x01, "Tape ",
0x02, "Printer ",
0x03, "Processor",
0x04, "Worm ",
0x05, "CDROM ",
0x06, "Scanner ",
0x07, "Opt-dev ",
0x08, "Jukebox ",
0x09, "Comm-dev ",
-1, "????"
};
/*
* we open ( if no -d option) the first *scsi*.device in the device list.
*/
#define SCSI_STRING "*scsi"
static char A_vers[] = "\0$VER: SCSIdevs\t" VERSION __AMIGADATE__;
UBYTE *ip_buf = NULL;
UBYTE *scsi_data = NULL;
UBYTE *scsi_sense = NULL;
UBYTE *dev_name = NULL;
MSGPORT *mp_ptr = NULL;
IOSTDREQ *io_ptr = NULL;
SCSICMD scsi_cmd;
int scsi_id = -1;
int on_off = -1;
UBYTE buffer[LINE_BUF];
int secno = -1;
int open_cnt = 0;
#define NNN 4 /* KLUGE TO ALLOW CDROM READS (2048 bytes) */
BOOL scsi_devs[8];
int scsi_devs_type[8];
char x_buf[RDB_LOCATION_LIMIT * SEC_LEN_512];
char buf_rdsk[SEC_LEN_512 * NNN];
char buf_part[SEC_LEN_512 * NNN];
ULONG next_part_block = -1;
RIGIDDISKBLOCK *p_rdb;
char p_buf[256];
int part_no;
BOOL raw_flag = FALSE;
char hdr_rdb[200] = "\
ID UNIT SIZE FS PARTITION PRI BUFFS\n\
~~ ~~~~ ~~~~ ~~ ~~~~~~~~~ ~~~ ~~~~~\n";
/*
* partition format string
*/
char fmt_rdb[100] = "%d %-10s %4dM %3s %-12s %4d %3d\n";
char hdr_dev[200] = "\
ID DEVICE REM VENDOR PRODUCT-STRING REV\n\
~~ ~~~~~~ ~~~ ~~~~~~ ~~~~~~~~~~~~~~ ~~~\n\
";
char fmt_dev[100] = "%d %10s %s %.8s %.16s %.4s\n";
/*********************************************************************
*
* main
*
*
***/
void
main (int argc, char **argv)
{
if (argc > 1)
{
if (strncmp (argv[1], "-d", 2) == 0)
{
dev_name = argv[1] + 2;
if (GetDevName (dev_name) == NULL)
{
printf ("Error : Cannot find \"%s\" in device list\n", dev_name);
exit (1);
}
}
else if (strncmp (argv[1], "-h", 2) == 0)
{
usage ("");
exit (0);
}
else
{
usage ("Error: Invalid option\n");
exit (0);
}
}
/*
* find a SCSI device, if no -d option
*/
if (dev_name == NULL)
{
if ((dev_name = GetDevName (SCSI_STRING)) == NULL)
{
usage ("Error : no *scsi*.device in device list\n");
hexit (1);
}
}
/*
* now set up structures etc for SCSI xfer
*/
if (init () == FALSE)
hexit (1);
/*
* scan SCSI bus, marking existence of devices in scsi_devs[]
*/
if (check_scsi_devices () == 0)
{
printf ("No SCSI devices found\n");
hexit (1);
}
printf ("\n%s", hdr_dev);
for (scsi_id = 0; scsi_id < 7; ++scsi_id)
{
if (scsi_devs[scsi_id] == TRUE)
{
char *qni = &inq_buf[scsi_id * MAX_DATA_LEN];
int dev_type = qni[0] & 0x1F;
char *dev = id2string (dev_type, devicetype);
char *m_rem = (qni[1] & 0x80) ? "Y" : "N";
char *vendor = &qni[8];
char *product = &qni[16];
char *rev = &qni[32];
printf (fmt_dev,
scsi_id, dev, m_rem, vendor, product, rev);
scsi_devs_type[scsi_id] = dev_type;
}
else
{
scsi_devs_type[scsi_id] = -1;
}
}
/*
* print header, then examine SCSI DISK devices for an RDB
*/
printf ("\n\n%s", hdr_rdb);
for (scsi_id = 0; scsi_id < 7; ++scsi_id)
{
// printf ("++++looking for SCSI ID %d\n", scsi_id);
if ((scsi_devs[scsi_id] == TRUE) && (scsi_devs_type[scsi_id] == 0x00))
{
// printf ("++++Found SCSI ID %d, and a Disk\n", scsi_id);
if (get_scsi_info (scsi_id) == SCSI_ERR)
{
printf ("\n%d ***SCSI READ ERROR***\n\n", scsi_id);
}
else
{
// printf ("++++Found SCSI ID %d, and a Disk - with no SCSI_ERR\n", scsi_id);
}
}
}
// printf ("++++Finished SCSI Id loop\n");
hexit (0);
}
/*********************************************************************
*
* check for a SCSI device
*
*/
int
check_scsi_devices ()
{
int j;
int count;
for (j = 0, count = 0; j < 7; ++j)
{
if (OpenDevice (dev_name, j, (IOREQUEST *) io_ptr, 0) == 0)
{
++open_cnt;
/*
* collect inquiry info
*/
inquiry (&inq_buf[j * MAX_DATA_LEN]);
scsi_devs[j] = TRUE;
++count;
CloseDevice ((IOREQUEST *) io_ptr);
--open_cnt;
// printf ("Found device at ID = %d\n", j);
}
else
{
scsi_devs[j] = FALSE;
}
}
return count;
}
/*********************************************************************
*
* Get data from RDB on disk
*
*
*/
RET_VAL
get_scsi_info (int id)
{
int j;
BOOL retval = GOOD;
if (OpenDevice (dev_name, id, (IOREQUEST *) io_ptr, 0) != 0)
{
return NO_DEV;
}
++open_cnt;
/*
*********** find RDSK block
*/
for (j = 0;;)
{
if (read_sec_scsi (buf_rdsk, j, 1) == FALSE)
{
retval = SCSI_ERR;
goto error;
}
if (strncmp (buf_rdsk, "RDSK", 4) == 0)
{
RIGIDDISKBLOCK *p = (RIGIDDISKBLOCK *) buf_rdsk;
/*
* check checksum
*/
if (checksum ((LONG *) p, p->rdb_SummedLongs) == FALSE)
{
printf ("\n********** RDSK block checksum error!\n");
retval = SCSI_ERR;
goto error;
}
next_part_block = p->rdb_PartitionList;
break;
}
if (++j == RDB_LOCATION_LIMIT)
{
retval = NO_RDB;
goto error;
}
}
/*
*********** loop through Partition Blocks
*/
for (part_no = 0;;)
{
PARTITIONBLOCK *p = (PARTITIONBLOCK *) buf_part;
if (read_sec_scsi (buf_part, next_part_block, 1) == FALSE)
{
retval = SCSI_ERR;
goto error;
}
if (strncmp (buf_part, "PART", 4) != 0)
{
printf ("No PART string in header\n");
retval = SCSI_ERR;
goto error;
}
/*
* check checksum
*/
if (checksum ((LONG *) p, p->pb_SummedLongs) == FALSE)
{
printf ("\n********** PART block checksum error!\n");
retval = SCSI_ERR;
goto error;
}
/*
* now print out interesting info
*/
print_Part_info (p);
next_part_block = p->pb_Next;
if (next_part_block == 0xFFFFFFFF)
{
break;
}
}
error:
CloseDevice ((IOREQUEST *) io_ptr);
--open_cnt;
return retval;
}
/*********************************************************************
*
*
*
*/
void
print_Part_info (PARTITIONBLOCK * ptr)
{
DOSENVEC *pe = (DOSENVEC *) & ptr->pb_Environment;
ULONG f = ptr->pb_Flags;
ULONG size;
ULONG bpcyl;
char *dostype;
char *boot;
bpcyl = pe->de_Surfaces * pe->de_BlocksPerTrack;
/*
* append partition name in BSTR form
*/
if (f & PBFF_BOOTABLE)
boot = " Boot";
else if (f & PBFF_NOMOUNT)
boot = "NonAutoMount";
else
boot = " AutoMount";
/*
* get bits of env structure
*/
size = ((pe->de_HighCyl - pe->de_LowCyl) * bpcyl) / (2 * 1024);
if (pe->de_DosType == 0X444F5300)
dostype = "OFS";
else if (pe->de_DosType == 0X444F5301)
dostype = "FFS";
else
dostype = "???";
printf (fmt_rdb,
scsi_id,
b2Cstr (&ptr->pb_DriveName[0]),
size,
dostype,
boot,
pe->de_BootPri,
pe->de_NumBuffers
);
}
/*********************************************************************
*
* Initialisation function
*
*
*/
BOOLEAN
init ()
{
if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem(0) Fail\n");
return FALSE;
}
if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem(1) Fail\n");
return FALSE;
}
if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
{
fprintf (stderr, "AllocMem(2) Fail\n");
return FALSE;
}
if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
{
fprintf (stderr, "CreatePort Fail\n");
return FALSE;
}
if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
{
fprintf (stderr, "CreateStdIO Fail\n");
return FALSE;
}
return TRUE;
}
/*********************************************************************
*
* function to read sectors from a starting sector #
*
* - uses scsi device directly
*/
BOOL
read_sec_scsi (char *ip_buf, int sec_start, int n_secs)
{
static struct CMD_XREAD
{
UBYTE cmd;
UBYTE lba[3];
UBYTE numb_secs;
UBYTE pad;
}
command =
{
SCSI_CMD_RD,
0, 0, 0,
0,
PAD
};
int err;
io_ptr->io_Command = HD_SCSICMD;
io_ptr->io_Length = sizeof (SCSICMD);
io_ptr->io_Data = (APTR) & scsi_cmd;
scsi_cmd.scsi_Command = (UBYTE *) & command;
scsi_cmd.scsi_CmdLength = sizeof (command);
scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
scsi_cmd.scsi_Data = (APTR) ip_buf;
scsi_cmd.scsi_Length = n_secs * SEC_LEN_512 * NNN;
scsi_cmd.scsi_SenseData = scsi_sense;
scsi_cmd.scsi_SenseLength = SENSE_LEN;
command.lba[2] = sec_start;
command.lba[1] = sec_start >> 8;
command.lba[0] = (sec_start >> 8) & 0x1F;
command.numb_secs = n_secs;
io_ptr->io_Offset = secno * TD_SECTOR; /* sector offset */
DoIO ((IOREQUEST *) io_ptr);
if ((err = io_ptr->io_Error) != 0)
{
/* DoIO error */
#if 0
fprintf (stderr, "Error : sec = %ld dec , %lXH , [%s]\n",
secno, secno, sense_errs (err));
#endif
return (FALSE);
}
return (TRUE);
}
/*********************************************************************
*
* searches DeviceList for a device name with a given string in it.
* - if found returns with a pointer to it, else NULL
*/
extern struct ExecBase *SysBase;
UBYTE *
GetDevName (char *grep)
{
LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
NODE *ln;
BOOL flag;
char *p1;
if (*(p1 = grep) == '\0')
{
return NULL;
}
else if (*p1 == '*') /* look for "*scsi" */
{
++p1;
flag = TRUE;
}
else
{
flag = FALSE;
}
for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
{
UBYTE *p = ln->ln_Name;
/*
* if first chara is a * (flag = TRUE) , search for pattern,
* else exact match
*/
if (flag == FALSE)
{
if (strcmp (p, p1) == 0)
{
return (ln->ln_Name);
}
}
else
/* look for "*scsi" */
{
while (*p && (*p != '.'))
{
if (strncmp (p, p1, strlen (p1)) == 0)
{
return (ln->ln_Name);
}
++p;
}
}
}
return (NULL); /* not found */
}
/*********************************************************************
*
* function to return an error string
*
*
*/
UBYTE *
err_str (int err)
{
static UBYTE *errors[] =
{
" cannot issue SCSI command to self ",
" DMA error ",
" illegal or unexpected SCSI phase ",
" SCSI parity error ",
" Select timed out ",
" status and/or sense error "
};
err -= 40;
if ((err < 0) || (err > 5))
return ("Error out-of-range");
else
return (errors[err]);
}
/*********************************************************************
*
* sense_errs function ; prints sense errors
*
*
*/
UBYTE *
sense_errs (int err)
{
static char buf[80];
typedef struct
{
BYTE code;
BYTE sense;
UBYTE *ptr;
}
S_ERRS;
/*
* only the likely, interesting ones filled in, e.g media errors
*/
static S_ERRS x[] =
{
0x00, 0x00, "No error",
0x01, 0x04, "?",
0x02, 0x04, "?",
0x03, 0x04, "?",
0x04, 0x02, "?",
0x06, 0x04, "?",
0x09, 0x04, "?",
0x10, 0x03, "?",
0x10, 0x04, "?",
0x11, 0x03, "?",
0x12, 0x03, "?",
0x13, 0x03, "?",
0x14, 0x03, "?",
0x15, 0x04, "Seek error ",
0x17, 0x01, "?",
0x18, 0x01, "?",
0x19, 0x03, "?",
0x1A, 0x05, "?",
0x20, 0x05, "Invalid command op code",
0x21, 0x05, "Illegal sector address",
0x24, 0x05, "?",
0x25, 0x05, "Invalid LUN",
0x26, 0x05, "Invalid field in parameter list",
0x29, 0x06, "?",
0x2A, 0x06, "?",
0x31, 0x03, "?",
0x32, 0x01, "?",
0x32, 0x03, "?",
0x40, 0x04, "?",
0x41, 0x04, "?",
0x42, 0x04, "Power-on diagnostic failure",
0x43, 0x04, "?",
0x45, 0x04, "Select / reselect failure ",
0x47, 0x04, "SCSI Interface Parity Error",
0x48, 0x0B, "?",
0x49, 0x0B, "Illegal message drive can't support",
-1, -1, "ILLEGAL sense!!"
};
int j = 0;
UBYTE *p;
char sense;
char code;
/*
* verify that sense data looks valid
*/
if (((scsi_cmd.scsi_Status & 2) == 0) ||
(scsi_cmd.scsi_SenseActual < OFFS_KEY))
{
return ("");
}
sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
code = scsi_cmd.scsi_SenseData[OFFS_CODE];
do
{
p = x[j].ptr;
if ((x[j].code == code) && (x[j].sense == sense))
{
return (p);
}
}
while (x[j++].code != -1);
sprintf (buf, "Sense error ; code = %XH, sense = %XH\n", code, sense);
return (buf);
}
/*********************************************************************
*
*
*
*/
BOOL
checksum (LONG * p, int n_longs)
{
int j;
LONG csum;
BOOL retval;
for (j = 0, csum = 0; j < n_longs; ++j)
{
csum += p[j];
}
retval = (csum == 0) ? TRUE : FALSE;
return retval;
}
/*********************************************************************
*
*
*
*/
void
hexit (int j)
{
// printf ("hexit: \n");
// printf ("hexit: DeleteStdIO\n");
DeleteStdIO (io_ptr);
if (mp_ptr)
{
// printf ("hexit: Deleteport, mp_ptr = %lx \n", mp_ptr);
DeletePort (mp_ptr);
}
if (ip_buf)
{
// printf ("hexit: ip_buf = %lx \n", ip_buf);
FreeMem (ip_buf, TD_SECTOR);
}
if (scsi_data)
{
// printf ("hexit: scsi_data = %lx \n", scsi_data);
FreeMem (scsi_data, MAX_DATA_LEN);
}
if (scsi_sense)
{
// printf ("hexit: scsi_sense = %lx\n", scsi_sense);
FreeMem (scsi_sense, SENSE_LEN);
}
//printf("open_cnt = %ld\n", open_cnt);
exit (j);
}
/*********************************************************************
*
* usage function
*
*
*/
void
usage (char *p)
{
static char *zz[] =
{
"Options:\n",
"-d ; specify SCSI device driver, e.g. -dgvpscsi.device\n",
" (default \"*scsi*.device\")\n",
"-h ; help (this message)\n",
"\n",
"Scans SCSI bus and reports on SCSI devices found. If the device is\n",
"a disk, a search is made for a Rigid Disk Block, and if found,\n",
"some elements of the RDB are printed.\n",
"" /* TERM */
};
int j = 0;
printf ("%s\n", p);
printf ("SCSIdevs Vers: %s %s - written by gduncan@werple.net.au\n",
VERSION, __AMIGADATE__);
printf ("\nUsage : SCSIdevs [-d<scsi-device-name>] [-h]\n");
while (*zz[j++])
printf ("%s", zz[j - 1]);
printf ("\n");
}
/*********************************************************************
*
*
*
*/
char *
b2Cstr (char *ptr)
{
int len = *ptr++;
return (mkCstr (ptr, len));
}
/*********************************************************************
*
*
*
*/
char *
mkCstr (char *ptr, int len)
{
static char buf[128];
strncpy (buf, ptr, len);
if (buf[len - 1] != '\0')
buf[len] = '\0';
return buf;
}
/*********************************************************************
*
* function to make an inquiry
*
*/
void
inquiry (char *ptr)
{
static SCSICMD6 command =
{
SCSI_CMD_INQ, /* 0x12 INQUIRY */
PAD,
PAD, /* Page Code */
PAD, /* Reserved */
0, /* Allocation length */
PAD /* Control */
};
static int err;
command.b4 = MAX_DATA_LEN; /* Allocation length = max. data length */
if ((err = DoScsiCmd ((UBYTE *) ptr, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "inquiry() Error : err=%ld , %s\n", err, sense_errs (err));
}
}
/*********************************************************************
*
*
*/
char *
id2string (int val, IDTOSTRING * m_ptr)
{
int j;
for (j = 0;; ++j)
{
if (m_ptr->code == val || m_ptr->code == -1)
return (char *) m_ptr->ptr;
++m_ptr;
}
}
/*********************************************************************
*
* function to use a scsi command
*
*/
int
DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
{
int i;
io_ptr->io_Length = sizeof (SCSICMD);
io_ptr->io_Data = (APTR) & scsi_cmd;
io_ptr->io_Command = HD_SCSICMD;
scsi_cmd.scsi_Data = (APTR) data;
scsi_cmd.scsi_Length = datasize;
scsi_cmd.scsi_SenseActual = 0;
scsi_cmd.scsi_SenseData = scsi_sense;
scsi_cmd.scsi_SenseLength = SENSE_LEN;
scsi_cmd.scsi_Command = cmd;
scsi_cmd.scsi_CmdLength = cmdsize;
scsi_cmd.scsi_Flags = flags;
(void) DoIO ((struct IORequest *) io_ptr);
if (scsi_cmd.scsi_SenseActual)
{
fprintf (stderr, "SENSE_DATA:");
for (i = 0; i < scsi_cmd.scsi_SenseActual; i++)
{
fprintf (stderr, " %02x", scsi_cmd.scsi_SenseData[i]);
}
fprintf (stderr, "\n");
}
return (io_ptr->io_Error);
}